// +build !no_istio_check

package exploit

import (
	"encoding/json"
	"io/ioutil"
	"log"
	"net/http"
	"strings"

	"github.com/cdk-team/CDK/pkg/plugin"
)

// plugin interface
type istioCheckS struct{}

func (p istioCheckS) Desc() string {
	return "Check was the shell in a istio(service mesh) network, please note that this feature will request http://httpbin.org/get. Usage: cdk run istio-check."
}

type isioHeader struct {
	XAmznTraceId         string `json:"X-Amzn-Trace-Id"`
	XB3Sampled           string `json:"X-B3-Sampled"`
	XB3Spanid            string `json:"X-B3-Spanid"`
	XB3Traceid           string `json:"X-B3-Traceid"`
	XEnvoyAttemptCount   string `json:"X-Envoy-Attempt-Count"`
	XEnvoyPeerMetadata   string `json:"X-Envoy-Peer-Metadata"`
	XEnvoyPeerMetadataId string `json:"X-Envoy-Peer-Metadata-Id"`
}

type response struct {
	Header isioHeader `json:"headers"`
}

func (p istioCheckS) Run() bool {

	var result = response{}
	// idea from https://blog.neargle.com/backup/CIS2020%20-%20Attack%20in%20a%20Service%20Mesh%20-%20Public.pdf
	resp, err := http.Get("http://httpbin.org/get")
	if err != nil {
		log.Fatalf("cannot fetch http://httpbin.org/get , get err: %v", err)
	}
	defer resp.Body.Close()

	err = json.NewDecoder(resp.Body).Decode(&result)
	if err != nil {
		log.Printf("cannot decode JSON: %v", err)
		bodyBytes, _ := ioutil.ReadAll(resp.Body)
		log.Fatalf("respone error: %s", string(bodyBytes))
	}

	// check X-Envoy-Peer-Metadata-Id
	if strings.Contains(result.Header.XEnvoyPeerMetadataId, "sidecar") {
		log.Println("the shell is in a istio(service mesh) network.")
		log.Printf("X-Envoy-Peer-Metadata-Id is %s.\n", result.Header.XEnvoyPeerMetadataId)
		log.Printf("X-Envoy-Peer-Metadata is %s.\n", result.Header.XEnvoyPeerMetadata)
		return true
	} else {
		log.Fatalf("the shell is not in a istio(service mesh) network.")
	}

	return false
}

func init() {
	exploit := istioCheckS{}
	plugin.RegisterExploit("istio-check", exploit)
}
